This page last changed on Feb 22, 2011 by kgomes.

As a part of the upgrade and configuration of our software development infrastructure at MBARI, we installed a continuous integration server. Here is a diagram of the overall structure of the software development infrastructure.

For the build server, the goal was to install Atlassian's Bamboo, Fisheye and Crucible products. In addition, we installed the SeleniumRC server to help in the automatic running of web client unit tests. Here are the steps:

  1. Install Java. jpackage-utils was already installed, so I went to java.sun.com and downloaded the jdk-6u23-linux-x64-rpm.bin.
  2. I had to run 'chmod a+x jdk-6u23-linux-x64-rpm.bin' to make sure I could execute the package.
  3. I then ran './jdk-6u23-linux-x64-rpm.bin'
  4. This expanded out to several .rpm files. In order to make sure I don't hit permissions issues, I moved all those files to the /tmp/java directory so I could run the install the rpm files using sudo.
  5. Then I ran 'sudo rpm -Uvh jdk-6u23-linux-amd64.rpm'
  6. Pat did something here to integrate it into the alternatives as I did not have permissions. The bottom line is that java got installed.
  7. I downloaded the Bamboo-3.0 standalone installation from atlassian to my Bamboo folder on my desktop.
  8. I downloaded the jtds dist zip file (1.2.5) to the Bamboo folder on my desktop.
    JTDS is already in Bamboo

    It turns out the Bamboo install already has jtds 1.2.2 installed so you don't need to do this unless you want to upgrade it.

  9. I created the /data/Bamboo directory to house the Bamboo working files and created the /opt/Bamboo to house the application itself.
  10. I unzipped and untarred the Bamboo download into the /opt directory which put it into the Bamboo directory I created.
  11. I cd'd into /opt/Bamboo/webapp/WEB-INF/classes and then edited the bamboo-init.properties file. In the file I uncommented the bamboo.home line and set it to:
    bamboo.home=/data/Bamboo
    
  12. I then started the server by cd'ing to /opt/Bamboo and running ./bamboo.sh start
  13. I then browsed to http://localhost:8085 and was prompted to enter the license key.
  14. I took the server ID provided and went to the Atlassian site and entered it as the id for a new license key.
  15. I grabbed the generated key and stuck it back into the localhost page asking for it.
  16. I then clicked on "Custom Installation" to configure things manually. The only things I changed are below:
    1. I changed the name field to "MBARI Bamboo"
    2. I changed the Base URL to "http://build-server.shore.mbari.org:8085"
    3. I chose an external database and chose Microsoft SQL Server 2005/2008
    4. I set the jdbc url to: jdbc:jtds:sqlserver://equinox.shore.mbari.org:51001/Bamboo;domain=SHORE
    5. The user was DB_Collaboration
    6. password is well, it just is.
  17. Clicked on continue and Bamboo setup the database
  18. I then chose to Create a new Bamboo home
  19. I used my MBARI username and password for the administration account until I can get it hooked up to Crowd.
  20. I then shutdown the Bamboo installation and configured it to use SSL per the instructions here. Cathy setup the SSL keystore in /usr/local/keystore/keystore.jks and I used that in the jetty.xml configuration file. I also had to follow the instructions and edit the bamboo.sh file to use the jetty.xml (it does not by default).

    Note that I also uncomented these lines in the 8085 port connector which disabled the 8085 port on all but localhost IP addresses to make sure people have to use the SSL connection.

    <Set name="Host">127.0.0.1</Set>
    <Set name="ConfidentialPort">8443</Set>
    <Set name="IntegralPort">8443</Set>
    
  21. I restarted Bamboo to verify that the SSL connection works.
  22. I then shutdown the Bamboo installation and followed the instructions here to integrate it with Crowd. Below are the specific things I had to do for our installation
    1. In order to keep the default groups of bamboo-admin and bamboo-users out of our LDAP, I created those two groups in the MBARI Crowd directory and then created a bambooadmin account that belongs to both. That meets the requirements of Bamboo and does not force our I.S. group to have to have bamboo-admin and bamboo-user groups in our LDAP.
    2. The rest of the configuration was pretty straightforward except for the fact that Crowd is now using SSL and the connection between build-server and crowd was over SSL. This caused much grief as the connection was not trusted so I finally found some instructions on how to get around that here. After I ran the program attached and installed the keystore in the java jre/lib/security directory, all was well and I could authenticate into Bamboo using MBARI's LDAP and MBARI Crowd directory.
  23. The last step was to get all this running as a different user.
    1. I shutdown bamboo.
    2. I then did a 'chown -R root:root /opt/Bamboo' to make sure that the default ownership of all the files was root
    3. I did a 'chown -R DB_Collaboration:DB_Collaboration /data/Bamboo' to make sure the DB_Collaboration account owned all the bamboo data.
    4. I then went in to the /opt/Bamboo directory and gave ownership of the following files and directories to DB_Collaboration.
      1. atlassian-bamboo.log
      2. logs
      3. /opt/Bamboo (so the bamboo.pid file can be created)
    5. I then created the /etc/init.d/bamboo script:
      #!/bin/sh
      # Startup script for bamboo
      #
      # chkconfig: 2345 99 01
      # description: Atlassian Bamboo
      # pidfile: /var/run/bamboo.pid
      . /etc/rc.d/init.d/functions
      BAMBOO_HOME=/data/Bamboo
      BAMBOO_INSTALL=/opt/Bamboo
      BAMBOO_USER=DB_Collaboration
      export BAMBOO_HOME
      NAME=bamboo
      BPID=${BAMBOO_INSTALL}/bamboo.pid
      PID=/var/run/${NAME}.pid
      cd ${BAMBOO_INSTALL}
      if [ _$1 = _condrestart ]; then
      su - ${BAMBOO_USER} -c "
      cd ${BAMBOO_INSTALL} &&
      ${BAMBOO_INSTALL}/bamboo.sh stop &&
      ${BAMBOO_INSTALL}/bamboo.sh start
      "
      else
      su - ${BAMBOO_USER} -c "
      cd ${BAMBOO_INSTALL} &&
      ${BAMBOO_INSTALL}/bamboo.sh $@
      "
      fi
      RC=$?
      if [ -f $BPID ]; then
      cp -- $BPID $PID
      touch /var/lock/subsys/${NAME}
      else
      rm -- $PID /var/lock/subsys/${NAME} 2>/dev/null
      fi
      exit $RC
      
  24. I made it executable by all and changed the ownership to root:root
  25. I then ran the following to configure it to start:
    sudo /sbin/chkconfig --add bamboo
    sudo /sbin/chkconfig bamboo on
    sudo /sbin/service bamboo start
    
  26. I then downloaded the selenium rc server jar file, put it in the /opt/selenium directory and created the following script and put it in /etc/init.d/selenium
    #!/bin/sh
    # chkconfig: 2345 99 01
    # description: Selenium RC Service Agent
    . /etc/rc.d/init.d/functions
    scriptFile=$(readlink -fn $(type -p $0))
    scriptDir=$(dirname $scriptFile)
    
    # This is the directory where selenium is installed
    applDir=/opt/selenium-rc
    
    # The service names
    serviceName=SeleniumRC
    serviceNameLo=SeleniumRC
    
    # The group that will be used to run the service
    serviceUser=DB_Collaboration
    serviceGroup=DB_Collaboration
    
    # This is the process id file
    pidFile=/opt/selenium-rc/selenium.pid
    
    # This is the log file where messages will be written
    serviceLogFile=/opt/selenium-rc/log/selenium.log
    
    # The java command to run
    javaCommand=java
    
    # The arguments to pass to the java command
    javaArgs="-jar selenium-server-standalone-2.0b2.jar"
    
    # The full java command line
    javaCommandLine="$javaCommand $javaArgs"
    
    javaCommandLineKeyword=selenium-server-standalone
    
    # The time to wait for the graceful shutdown to work before sending SIGKILL
    maxShutdownTime=15
    
    # This is a function to create a file and make it writable by the process group
    function makeFileWritable {
      local filename="$1"
      touch $filename || return 1
      chgrp $serviceGroup $filename || return 1
      chmod g+w $filename || return 1
      return 0;
    }
    
    # This function checks if the process with the pid that is passed in is running
    function checkProcessIsRunning {
      local pid="$1"
      if [ -z "$pid" -o "$pid" == " " ]; then return 1; fi
      if [ ! -e /proc/$pid ]; then return 1; fi
      return 0;
    }
    
    # This function checks to see if the process id is the one that we started 
    function checkProcessIsOurService {
      local pid="$1"
      if [ "$(ps -p $pid --no-headers -o comm)" != "$javaCommand" ];
      then return 1; fi
      grep -q "$javaCommandLineKeyword" /proc/$pid/cmdline
      if [ $? -ne 0 ]; then return 1; fi
      return 0;
    }
    
    # This actually starts the service running
    function startServiceProcess {
      cd $applDir || return 1
      rm -f $pidFile
      makeFileWritable $pidFile || return 1
      makeFileWritable $serviceLogFile || return 1
      cmd="nohup $javaCommandLine >>$serviceLogFile 2>&1 & echo \$! >$pidFile"
      sudo -u $serviceUser $SHELL -c "$cmd" || return 1
      # $SHELL -c "$cmd" || return 1
      sleep 0.1
      pid="$(<$pidFile)"
      if checkProcessIsRunning $pid; then :; else
        echo "$serviceName service started, log file $serviceLogFile."
        return 1
      fi
        return 0;
    }
    
    # This function stops the process
    function stopServiceProcess {
      kill $pid || return 1
      for ((i=0; i<maxShutdownTime*10; i++)); do
        checkProcessIsRunning $pid
        if [ $? -ne 0 ]; then
          rm -f $pidFile
          return 0
        fi
        sleep 0.1
      done
      echo "$serviceName $maxShutdownTime time exceeded, sending SIGKILL"
      kill -s KILL $pid || return 1
      local killWaitTime=15
      for ((i=0; i<killWaitTime*10; i++)); do
        checkProcessIsRunning $pid
        if [ $? -ne 0 ]; then
          rm -f $pidFile
          return 0
        fi
        sleep 0.1
      done
      echo "Error: $serviceName $maxShutdownTime+$killWaitTime seconds past and could not shutdown"
      return 1;
    }
    
    # This function grabs the process ID
    function getServicePID {
      if [ ! -f $pidFile ]; then return 1; fi
      pid="$(<$pidFile)"
      checkProcessIsRunning $pid || return 1
      checkProcessIsOurService $pid || return 1
      return 0;
    }
    
    # The function that checks to see if the service is running and if not, starts it
    function startService {
      getServicePID
      if [ $? -eq 0 ]; then echo "$serviceName already running"; return 0; fi
      echo "$serviceName starting"
      startServiceProcess
      if [ $? -ne 0 ]; then return 1; fi
      return 0;
    }
    
    # This function checks to see if the process is running and if so, calls the function to stop it
    function stopService {
      getServicePID
      if [ $? -ne 0 ]; then echo "$serviceName not running"; return 0; fi
      echo "$serviceName stopping"
      stopServiceProcess
      if [ $? -ne 0 ]; then return 1; fi
      return 0;
    }
    
    # This function check if the service is running or not
    function checkServiceStatus {
      echo -n "$serviceName appears to be "
      if getServicePID; then
        echo "running."
      else
        echo "stopped."
      fi
      return 0;
    }
    
    # This is the main function that gets called first
    function main {
      case "$1" in
        start)
          startService
          ;;
        stop)
          stopService
          ;;
        restart)
          stopService && startService
          ;;
        status)
          checkServiceStatus
          ;;
        *)
          echo "Usage: $0 {start|stop|restart|status}"
          exit 1
          ;;
      esac
    }
    
    # Call the main function and pass in the argument
    main $1 
    
  27. I then ran sudo /sbin/chkconfig --add selenium
  28. Then sudo /sbin/service selenium start

    I am having trouble getting it to start on reboot. Works fine from the command line, but not from reboot.

  29. I then downloaded maven and ant and unpacked them both to /opt and create /opt/maven and /opt/ant symbolic links to them respectively.
  30. I then created two scripts java-dev.csh and java-dev.sh and put them in the /etc/profile.d directory and made them exectuable so that ant and maven were added to the default paths.
    1. java-dev.csh
      # Set some Java development environment variables
      setenv JAVA_HOME "/usr/java/latest"
      setenv ANT_HOME "/opt/ant"
      setenv M2_HOME "/opt/maven"
      
      # Add the ant and maven bins to the path
      setenv PATH "${PATH}:/opt/ant/bin:/opt/maven/bin"
      
    2. java-dev.sh
      # Some Java development variables
      JAVA_HOME=/usr/java/latest
      ANT_HOME=/opt/ant
      M2_HOME=/opt/maven
      
      export JAVA_HOME ANT_HOME M2_HOME
      
      # Add the ant and maven bin directories to the path
      pathmunge /opt/ant/bin
      pathmunge /opt/maven/bin
      
Document generated by Confluence on Feb 03, 2026 16:22